<?php
namespace Session;

use Swoft\Bean\Annotation\Mapping\Bean;
use Session\Handler\LifetimeInterface;
use Session\Handler\RedisSessionHandler;
use Swoft\Bean\BeanFactory;

/**
 * @Bean(scope=Bean::PROTOTYPE)
 */
class SessionManager
{

    const SESSION_KEY = 'session';

    /**
     * The session handlers
     *
     * @var array
     */
    protected $handlers = [
        'redis' => RedisSessionHandler::class
    ];

    /**
     *
     * @var SessionManager[]
     */
    private static $mapperObject = [];

    /**
     *
     * @var array
     */
    protected $config = [
        'driver' => 'redis',
        'name' => 'ShopMG-SESSION',
        'lifetime' => 3600,
        'expire_on_close' => false,
        'encrypt' => false
    ];

    /**
     * Create a handler by config
     *
     * @return \SessionHandlerInterface
     * @throws \InvalidArgumentException
     */
    public function createHandlerByConfig(): \SessionHandlerInterface
    {
        if (! isset($this->getConfig()['driver'])) {
            throw new \InvalidArgumentException('Session driver required');
        }
        $handler = $this->getHandler($this->getConfig()['driver']);
        $handler instanceof LifetimeInterface && $handler->setLifetime($this->getConfig()['lifetime']);
        return $handler;
    }

    /**
     * Get a handler by name
     *
     * @param string $name            
     * @return \SessionHandlerInterface
     * @throws \InvalidArgumentException
     */
    public function getHandler(string $name): \SessionHandlerInterface
    {
        $name = strtolower($name);
        $this->isValidate($name);
        return BeanFactory::getBean($this->handlers[$name]);
    }

    /**
     *
     * @param string $name            
     * @throws \InvalidArgumentException
     */
    protected function isValidate(string $name)
    {
        if (! array_key_exists($name, $this->handlers)) {
            throw new \InvalidArgumentException('Invalid session handler');
        }
    }

    /**
     *
     * @return array
     */
    public function getConfig(): array
    {
        return $this->config;
    }

    /**
     *
     * @param array $config            
     * @return SessionManager
     */
    public function setConfig(array $config): self
    {
        $this->config = $config;
        return $this;
    }

    /**
     *
     * @return SessionInterface
     */
    public function getSession(): SessionInterface
    {
        return static::$mapperObject[static::SESSION_KEY];
    }

    /**
     *
     * @param SessionInterface $session            
     * @return static
     */
    public function setSession($session): self
    {
        static::$mapperObject = [
            self::SESSION_KEY => $session
        ];
        return $this;
    }
}
